home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: CompositeClassDriver.c Contains: Core functionality to Composite Class Driver Version: xxx put version here xxx Copyright: © 1997-2000 by Apple Computer, Inc., all rights reserved. */ #include <Types.h> #include <Devices.h> #include <processes.h> #include <DriverServices.h> #include <USB.h> #include "CompositeClassDriver.h" #define debugBuild 0 #if debugBuild #define debugLevel 2 #define debugStatus(ref, str, val) USBExpertStatusLevel(debugLevel, ref, kCompositeDriverName str, val); #else #define debugLevel 5 #define debugStatus(ref, str, val) #endif usbCompositePBStruct newInterfacesPB; void InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock) { paramblock->usbReference = theDeviceRef; paramblock->usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; paramblock->pbLength = sizeof(usbCompositePBStruct); paramblock->pbVersion = kUSBCurrentPBVersion; paramblock->usb.cntl.WIndex = 0; paramblock->usbBuffer = nil; paramblock->usbStatus = kUSBNoErr; paramblock->usbReqCount = 0; paramblock->usbActCount = 0; paramblock->usb.cntl.WValue = 0; paramblock->usbFlags = 0; } /* This is copied wholesale from the UIM via the hub driver. This table contains the list of errata that are necessary for known problems with particular hub The format is vendorID, product ID, lowest revisionID needing errata, highest rev needing errata, errataBits The result of all matches is ORed together, so more than one entry may match. Typically for a given errata a list of hubs revisions that this applies to is supplied. */ enum{ kErrataNoReset = 1 }; typedef struct { UInt16 vendID; UInt16 deviceID; UInt16 revisionLo; UInt16 revisionHi; UInt32 errata; }ErrataListEntry; static ErrataListEntry errataList[] = { /* For the Cherry 3 port KB, radar 2358706 With the composite driver doing a reset as its first action (fixes a mass storage problem, but sounds like a bad idea) the Cherry 3 prot KB does not work at boot, but does if hot plugged. It looks like all the resets at composite replacement are sending it screwy. It looks to be working fine, but never gives any status change on its interrupt endpoint. */ {0x046a, 0x001, 0x0000, 0x9999, kErrataNoReset} // Cherry 3 port KB }; #define errataListLength (sizeof(errataList)/sizeof(ErrataListEntry)) static UInt32 GetErrataBits(USBDeviceDescriptor *desc) { UInt32 vendID, deviceID, revisionID; ErrataListEntry *entryPtr; UInt32 i, errata = 0; // get this chips vendID, deviceID, revisionID vendID = USBToHostWord(desc->vendor); deviceID = USBToHostWord(desc->product); revisionID = USBToHostWord(desc->devRel); for(i=0, entryPtr = errataList; i<errataListLength; i++, entryPtr++){ if (vendID == entryPtr->vendID && deviceID == entryPtr->deviceID && revisionID >= entryPtr->revisionLo && revisionID <= entryPtr->revisionHi){ errata |= entryPtr->errata; // we match, add this errata to our list } } return(errata); } Boolean immediateError(OSStatus err) { return((err != kUSBPending) && (err != kUSBNoErr) ); } void CompositeDeviceInitiateTransaction(USBPB *pb) { register usbCompositePBStruct *pCompositePB; OSStatus myErr; pCompositePB = (usbCompositePBStruct *)(pb); if (pCompositePB->expertTerminatePending) // TCC <USB16> return; pCompositePB->transDepth++; if ((pCompositePB->transDepth < 0) || (pCompositePB->transDepth > 1)) { USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": Illegal Transaction Depth", pCompositePB->pb.usbRefcon); } if (pCompositePB->driverRemovalPending) { pCompositePB->pb.usbRefcon = kReturnFromDriver; return; } switch(pCompositePB->pb.usbRefcon & ~kRetryTransaction) { case kResetDevice: debugStatus(pCompositePB->pb.usbReference, ": kResetDevice resetting ", newInterfacesPB.busPowerAvailable); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBResetDevice(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": kResetDevice - immediate error", myErr); } break; case kGetAConfiguration: debugStatus(pCompositePB->pb.usbReference, ": kGetAConfiguration getting ", newInterfacesPB.busPowerAvailable); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); // Find the first configuration with any interface which satisfy the power requirements pCompositePB->pb.usbReqCount = newInterfacesPB.busPowerAvailable; pCompositePB->pb.usbClassType = 0; pCompositePB->pb.usbSubclass = 0; pCompositePB->pb.usbProtocol = 0; pCompositePB->pb.usb.cntl.WValue = 0; pCompositePB->pb.usb.cntl.WIndex = 0; pCompositePB->pb.usbOther = 0xff; // Find primary interface, not alts pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBFindNextInterface(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": USBFindNextInterface (#1) - immediate error", myErr); } break; case kSetConfig: debugStatus(pCompositePB->pb.usbReference, ": kSetConfig setting ", pCompositePB->currentConfiguration); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); pCompositePB->pb.usb.cntl.WValue = pCompositePB->currentConfiguration; pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBSetConfiguration(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": USBSetConfiguration - immediate error", myErr); } break; case kAllocInterfaces: InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); pCompositePB->pb.usbReqCount = pCompositePB->interfaceCount * sizeof(interface); debugStatus(pCompositePB->pb.usbReference, ": kAllocInterfaces allocating ", pCompositePB->pb.usbReqCount); pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBAllocMem(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": USBAllocMem - immediate error", myErr); } break; case kGetConfigDesc: debugStatus(pCompositePB->pb.usbReference, ": kGetConfigDesc new ", pCompositePB->currentConfiguration); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); pCompositePB->pb.usb.cntl.WValue = pCompositePB->currentConfiguration; pCompositePB->pb.usbBuffer = &pCompositePB->configDescriptor; // put it here pCompositePB->pb.usbReqCount = sizeof(USBConfigurationDescriptor); // at most this size pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBGetConfigurationDescriptor(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": USBGetConfigurationDescriptor - immediate error", myErr); } break; case kSetRemoteWakeup: debugStatus(pCompositePB->pb.usbReference, ": kSetRemoteWakeup doing", pCompositePB->pb.usbReference); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); pCompositePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice); pCompositePB->pb.usb.cntl.BRequest = kUSBRqSetFeature; pCompositePB->pb.usb.cntl.WValue = kUSBFeatureDeviceRemoteWakeup; pCompositePB->pb.usb.cntl.WIndex = 0; pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBDeviceRequest(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": kSetRemoteWakeup - immediate error", myErr); } break; case kNewInterfaceRef: debugStatus(pCompositePB->pb.usbReference, ": kNewInterfaceRef new ", pCompositePB->currentInterface); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); // Note: pCompositePB->usb.cntl.WIndex will be set to zero by InitParamBlock // so set it again to pCompositePB->interfaceIndex before calling USBNewInterfaceRef pCompositePB->pb.usb.cntl.WIndex = pCompositePB->currentInterface; pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBNewInterfaceRef(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": kNewInterfaceRef - immediate error", myErr); } break; case kGetInterfaceDesc: debugStatus(pCompositePB->pb.usbReference, ": kGetInterfaceDesc", pCompositePB->interfaces[pCompositePB->interfaceIndex].ref); InitParamBlock(pCompositePB->interfaces[pCompositePB->interfaceIndex].ref, &pCompositePB->pb); pCompositePB->pb.usb.cntl.WIndex = 0; // Get me the first one pCompositePB->pb.usbOther = kUSBInterfaceDesc; // Get me an interface descriptor pCompositePB->pb.usbBuffer = &pCompositePB->interfaces[pCompositePB->interfaceIndex].desc; // put it here pCompositePB->pb.usbReqCount = sizeof(USBInterfaceDescriptor); // at most this size debugStatus(pCompositePB->pb.usbReference, ": kGetInterfaceDesc", pCompositePB->interfaces[pCompositePB->interfaceIndex].ref); // *(long *)pCompositePB->pb.usbBuffer = 0; pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBFindNextAssociatedDescriptor(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": kGetInterfaceDesc - immediate error", myErr); } break; case kFindNextInterface: debugStatus(pCompositePB->pb.usbReference, ": kFindNextInterface curr ", pCompositePB->currentInterface); InitParamBlock(pCompositePB->deviceRef, &pCompositePB->pb); pCompositePB->pb.usb.cntl.WValue = pCompositePB->currentConfiguration; // Find the first configuration with any interface which satisfy the power requirements pCompositePB->pb.usbReqCount = newInterfacesPB.busPowerAvailable; pCompositePB->pb.usbClassType = 0; pCompositePB->pb.usbSubclass = 0; pCompositePB->pb.usbProtocol = 0; pCompositePB->pb.usb.cntl.WValue = pCompositePB->currentConfiguration; pCompositePB->pb.usb.cntl.WIndex = pCompositePB->currentInterface; pCompositePB->pb.usbOther = 0xff; // Find primary interface, not alts pCompositePB->pb.usbRefcon |= kCompletionPending; pCompositePB->pb.usbCompletion = (USBCompletion)CompositeDeviceCompletionProc; myErr = USBFindNextInterface(pb); if(immediateError(myErr)) { pCompositePB->pb.usbRefcon &= ~kCompletionPending; USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": kFindNextInterface - immediate error", myErr); } break; default: USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName" - Transaction initiated with bad refcon value", pCompositePB->pb.usbRefcon); pCompositePB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } // At this point the control is returned to the system. If a USB transaction // has been initiated, then it will call the Complete procs // (below) to handle the results of the transaction. } void CompositeDeviceCompletionProc(USBPB *pb) { register usbCompositePBStruct *pCompositePB; static entryCounter = 0; pCompositePB = (usbCompositePBStruct *)(pb); if (pCompositePB->expertTerminatePending) // TCC <USB16> return; pCompositePB->transDepth--; if ((pCompositePB->transDepth < 0) || (pCompositePB->transDepth > 1)) { USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName" - Illegal Transaction Depth", pCompositePB->transDepth); } if(pCompositePB->pb.usbStatus == kUSBDevicePowerProblem) { if((pCompositePB->pb.usbRefcon & ~(kCompletionPending + kReturnFromDriver)) == kGetAConfiguration) { USBExpertStatus(pCompositePB->pb.usbReference, kCompositeDriverName": sending power note and giving up", pCompositePB->pb.usbStatus); USBExpertSetDevicePowerStatus(pCompositePB->pb.usbReference, 0, 0, kUSBDevicePower_BusPowerInsufficient, pCompositePB->busPowerAvailable, kUSB500mAAvailable); // TC: <USB67> pCompositePB->pb.usbRefcon = kReturnFromDriver; return; } if((pCompositePB->pb.usbRefcon & ~(kCompletionPending + kReturnFromDriver)) == kSetConfig) { USBExpertStatus(pCompositePB->pb.usbReference, kCompositeDriverName": kSetConfig gives power problem, must have 0mA to play with", pCompositePB->pb.usbStatus); pCompositePB->pb.usbRefcon = kReturnFromDriver; return; } USBExpertStatus(pCompositePB->pb.usbReference, kCompositeDriverName": power problem in unexpected state", pCompositePB->pb.usbRefcon); } if ((pCompositePB->pb.usbStatus == kUSBEndpointStallErr) && (pCompositePB->pb.usbRefcon & ~(kCompletionPending + kReturnFromDriver)) == kSetRemoteWakeup){ USBExpertStatus(pCompositePB->pb.usbReference, kCompositeDriverName": Device does not support RemoteWakeup (should look in the descriptor)", pCompositePB->configDescriptor.attributes); pCompositePB->pb.usbStatus = kUSBNoErr; } if((pCompositePB->pb.usbStatus != kUSBNoErr) && (pCompositePB->pb.usbStatus != kUSBPending)) { USBExpertStatus(pCompositePB->pb.usbReference, kCompositeDriverName": Completion Error", pCompositePB->pb.usbStatus); pCompositePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); pCompositePB->pb.usbRefcon |= kRetryTransaction; pCompositePB->retryCount--; if (!pCompositePB->retryCount) { USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName": Too many retries", pCompositePB->pb.usbRefcon); pCompositePB->pb.usbRefcon = kReturnFromDriver; return; } } else { pCompositePB->pb.usbRefcon &= ~kRetryTransaction; pCompositePB->retryCount = kCompositeRetryCount; } if (pCompositePB->pb.usbRefcon & kCompletionPending) { pCompositePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); switch(pCompositePB->pb.usbRefcon) { case kResetDevice: /* Device is not reset */ debugStatus(pCompositePB->pb.usbReference, ": kResetDevice reset ", newInterfacesPB.busPowerAvailable); pCompositePB->pb.usbRefcon = kGetAConfiguration; break; case kGetAConfiguration: debugStatus(pCompositePB->pb.usbReference, ": kGetAConfiguration got ", pCompositePB->pb.usb.cntl.WValue); // usb.cntl.WValue has the configuration value // usb.cntl.WIndex has the first interface number pCompositePB->currentConfiguration = pCompositePB->pb.usb.cntl.WValue; pCompositePB->currentInterface = pCompositePB->pb.usb.cntl.WIndex; pCompositePB->interfaceIndex = 0; pCompositePB->pb.usbRefcon = kSetConfig; break; case kSetConfig: debugStatus(pCompositePB->pb.usbReference, ": kSetConfig count ", pCompositePB->pb.usbOther); pCompositePB->interfaceCount = pCompositePB->pb.usbOther; pCompositePB->pb.usbRefcon = kAllocInterfaces; break; case kAllocInterfaces: if(pCompositePB->pb.usbActCount < pCompositePB->interfaceCount * sizeof(interface)) { USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName"kAllocInterfaces - not enough memory allocated", pCompositePB->pb.usbActCount); pCompositePB->pb.usbRefcon = kReturnFromDriver; } else { pCompositePB->interfaces = pCompositePB->pb.usbBuffer; pCompositePB->pb.usbRefcon = kGetConfigDesc; } break; case kGetConfigDesc: debugStatus(pCompositePB->pb.usbReference, ": kGetConfigDesc ", pCompositePB->pb.usbActCount); if(pCompositePB->pb.usbActCount < kUSBConfigDescriptorLength) { USBExpertStatusLevel(2, pCompositePB->pb.usbReference, kCompositeDriverName": kGetConfigDesc - got bad descriptor", pCompositePB->pb.usbActCount); pCompositePB->pb.usbRefcon = kNewInterfaceRef; } else { pCompositePB->pb.usbRefcon = (pCompositePB->configDescriptor.attributes & kUSBAtrRemoteWakeup) ? kSetRemoteWakeup : kNewInterfaceRef; } break; case kSetRemoteWakeup: debugStatus(pCompositePB->pb.usbReference, ": kSetRemoteWakeup ", pCompositePB->pb.usbReference); pCompositePB->pb.usbRefcon = kNewInterfaceRef; break; case kNewInterfaceRef: pCompositePB->pb.usbRefcon = kReturnFromDriver; /* save the new interface ref for this interface */ debugStatus(pCompositePB->pb.usbReference, ": kNewInterfaceRef ", pCompositePB->pb.usbReference); pCompositePB->interfaces[pCompositePB->interfaceIndex].ref = pCompositePB->pb.usbReference; pCompositePB->pb.usbRefcon = kGetInterfaceDesc; break; case kGetInterfaceDesc: debugStatus(pCompositePB->pb.usbReference, ": kGetInterfaceDesc result", *(long *)pCompositePB->pb.usbBuffer); if(pCompositePB->pb.usbActCount < kUSBInterfaceDescriptorLength) { USBExpertStatusLevel(2, pCompositePB->pb.usbReference, kCompositeDriverName": kGetInterfaceDesc - got bad descriptor", pCompositePB->pb.usbActCount); } else { // pCompositePB->interfaces[pCompositePB->interfaceIndex].desc = *(USBInterfaceDescriptor *)pCompositePB->pb.usbBuffer; USBExpertInstallInterfaceDriver(pCompositePB->interfaces[pCompositePB->interfaceIndex].ref, &pCompositePB->deviceDescriptor, pCompositePB->pb.usbBuffer, pCompositePB->deviceRef, 0); } /* if there's more interfaces, find them */ pCompositePB->interfaceIndex++; if (pCompositePB->interfaceIndex < pCompositePB->interfaceCount) { pCompositePB->pb.usbRefcon = kFindNextInterface; } else { pCompositePB->interfacesRead = true; pCompositePB->pb.usbRefcon = kReturnFromDriver; } break; case kFindNextInterface: if(pCompositePB->currentConfiguration != pCompositePB->pb.usb.cntl.WValue) { USBExpertStatusLevel(2, pCompositePB->pb.usbReference, kCompositeDriverName": kFindNextInterface - Interface found is not in correct configuration", pCompositePB->pb.usb.cntl.WValue); pCompositePB->pb.usbRefcon = kReturnFromDriver; } else { pCompositePB->currentInterface = pCompositePB->pb.usb.cntl.WIndex; pCompositePB->pb.usbRefcon = kNewInterfaceRef; } break; default: USBExpertFatalError(pCompositePB->pb.usbReference, kUSBInternalErr, kCompositeDriverName" - Transaction completed with a bad refcon value", pCompositePB->pb.usbRefcon); pCompositePB->pb.usbRefcon = kReturnFromDriver; break; } } if ( !(pCompositePB->pb.usbRefcon & kReturnFromDriver) && (!pCompositePB->driverRemovalPending)) { CompositeDeviceInitiateTransaction(pb); } } // entry points, moved from CompositeDriverDescription.c // hubDriverInitInterface function // Called to initialize driver for an individual interface - either by expert or // internally by driver OSStatus CompositeDriverInitInterface( UInt32 interfaceNum, USBInterfaceDescriptor *interfaceDesc, USBDeviceDescriptor *deviceDesc, USBDeviceRef device) { #pragma unused (interfaceNum) #pragma unused (interfaceDesc) #pragma unused (deviceDesc) #pragma unused (device) return (OSStatus)kUSBNoErr; } static OSStatus removeInterfaces(void) { OSStatus myErr; OSStatus status = kUSBNoErr; static UInt32 interfacenum = 0; newInterfacesPB.driverRemovalPending = true; if (interfacenum == 0) newInterfacesPB.pb.usbStatus = kUSBNoErr; if (newInterfacesPB.pb.usbStatus == kUSBPending) { USBExpertStatusLevel(5, newInterfacesPB.deviceRef, kCompositeDriverName": Waiting for Dispose/Deallocate to complete", newInterfacesPB.pb.usbRefcon); status = kUSBInternalErr; } else { if (interfacenum < newInterfacesPB.interfaceCount) { USBExpertRemoveInterfaceDriver(newInterfacesPB.interfaces[interfacenum].ref); InitParamBlock(newInterfacesPB.interfaces[interfacenum].ref, &newInterfacesPB.pb); newInterfacesPB.pb.usbRefcon = 0; newInterfacesPB.pb.usbCompletion = (USBCompletion)kUSBNoCallBack; myErr = USBDisposeInterfaceRef(&newInterfacesPB.pb); if(immediateError(myErr)) { USBExpertFatalError(newInterfacesPB.interfaces[interfacenum].ref, kUSBInternalErr, kCompositeDriverName" - USBDisposeInterfaceRef - immediate error", myErr); } interfacenum++; status = kUSBDeviceBusy; } else { if (newInterfacesPB.interfaces) { InitParamBlock(newInterfacesPB.deviceRef, &newInterfacesPB.pb); newInterfacesPB.pb.usbRefcon = 0; newInterfacesPB.pb.usbBuffer = newInterfacesPB.interfaces; newInterfacesPB.pb.usbCompletion = (USBCompletion)kUSBNoCallBack; myErr = USBDeallocMem(&newInterfacesPB.pb); if(myErr != noErr) { USBExpertStatus(newInterfacesPB.deviceRef, kCompositeDriverName": error disposing descriptors", myErr); } newInterfacesPB.interfaces = nil; } interfacenum = 0; // Ready for next time status = noErr; } } return(status); } OSStatus CompositeDriverNotifyProc(UInt32 notification, void *pointer, UInt32 refcon) { OSStatus status = kUSBNoErr; UInt32 count = 0; USBPB *pb; switch (notification) { case kNotifyChildMessage: USBExpertStatus(newInterfacesPB.deviceRef, kCompositeDriverName": child message from", refcon); pb = pointer; if (newInterfacesPB.pb.usbRefcon & kCompletionPending) { USBExpertStatusLevel(3, newInterfacesPB.deviceRef, kCompositeDriverName": busy for child message", pb->usb.hub.Request); status = kUSBDeviceBusy; } else { if(pb->usb.hub.Request == kUSBHubPortResetRequest) { newInterfacesPB.expertTerminatePending = true; do{ debugStatus(newInterfacesPB.deviceRef, kCompositeDriverName", Reset: Removing interfaces", 0); status = removeInterfaces(); }while(status == kUSBDeviceBusy); if(status == noErr) { debugStatus(newInterfacesPB.deviceRef, kCompositeDriverName", Reset: Interfaces removed", 0); newInterfacesPB.expertTerminatePending = false; newInterfacesPB.driverRemovalPending = false; newInterfacesPB.pb.usbRefcon = kResetDevice; /* Start out at first state */ CompositeDeviceInitiateTransaction(&newInterfacesPB.pb); } else { USBExpertStatusLevel(1, newInterfacesPB.deviceRef, kCompositeDriverName": error during driver remove", status); } } else if(pb->usb.hub.Request == kUSBHubPortSuspendRequest) { if(newInterfacesPB.interfaceCount > 1) { USBExpertStatusLevel(3, newInterfacesPB.deviceRef, kCompositeDriverName": could not suspend with multipleinterfaces", newInterfacesPB.interfaceCount); status = kUSBUnknownDeviceErr; } else { USBExpertStatusLevel(3, newInterfacesPB.deviceRef, kCompositeDriverName": passing single suspend request up", newInterfacesPB.interfaceCount); // If there is one interface, send this message to parent of the composite device (hub) status = kUSBUnknownRequestErr; // Use this as a signal to tel USL to send it on } } else { USBExpertStatusLevel(1, newInterfacesPB.deviceRef, kCompositeDriverName": unknown child message", pb->usb.hub.Request); status = kUSBUnknownRequestErr; } } break; case kNotifyExpertTerminating: // TCC <USB15> newInterfacesPB.expertTerminatePending = true; while (count < newInterfacesPB.interfaceCount) USBExpertRemoveInterfaceDriver(newInterfacesPB.interfaces[count++].ref); return(noErr); break; case kNotifyDriverBeingRemoved: newInterfacesPB.driverRemovalPending = true; if (newInterfacesPB.pb.usbRefcon & kCompletionPending) { USBExpertStatus(newInterfacesPB.deviceRef, kCompositeDriverName": Waiting for transaction to complete", newInterfacesPB.pb.usbRefcon); status = kUSBDeviceBusy; } else { status = removeInterfaces(); } break; default: break; } return status; } // Hardware Validation // Called upon load by Expert OSStatus CompositeDriverValidateHW(USBDeviceRef device, USBDeviceDescriptor *desc) { #pragma unused (device) #pragma unused (desc) return (OSStatus)kUSBNoErr; } // Initialization function // Called upon load by Expert OSStatus CompositeDriverInitialize (USBDeviceRef device, USBDeviceDescriptorPtr pDesc, UInt32 busPowerAvailable) { // don't let a race condition occur; prevent finalizing until we're all done. DeviceInitialize(device, pDesc, busPowerAvailable); return (OSStatus)kUSBNoErr; } // Termination function // Called by Expert when driver is being shut down OSStatus CompositeDriverFinalize(USBDeviceRef theDeviceRef, USBDeviceDescriptorPtr pDesc) { #pragma unused (pDesc) USBExpertStatus(theDeviceRef, kCompositeDriverName" - Finalize", 0); return (OSStatus)kUSBNoErr; } void DeviceInitialize(USBDeviceRef device, USBDeviceDescriptorPtr pDeviceDescriptor, UInt32 busPowerAvailable) { static Boolean beenThereDoneThat = false; UInt32 errataBits; if(beenThereDoneThat) { USBExpertFatalError(device, kUSBInternalErr, kCompositeDriverName" is not reentrant!", 0); return; } beenThereDoneThat = true; newInterfacesPB.driverRemovalPending = false; newInterfacesPB.expertTerminatePending = false; newInterfacesPB.deviceRef = device; newInterfacesPB.deviceDescriptor = *pDeviceDescriptor; newInterfacesPB.busPowerAvailable = busPowerAvailable; newInterfacesPB.delayLevel = 0; newInterfacesPB.transDepth = 0; newInterfacesPB.retryCount = kCompositeRetryCount; InitParamBlock(device, &newInterfacesPB.pb); errataBits = GetErrataBits(pDeviceDescriptor); if(errataBits != 0) { USBExpertStatusLevel(3, device, kCompositeDriverName"Using errata:", errataBits); } if((USBGetVersion() & 0xfff00000) == 0x01300000) // 1.3.(5|6) had the hub reset memory corruption bug { // refuse to run mismatched and ROM driver will be used. USBExpertStatusLevel(1,device, kCompositeDriverName" - DeviceInitialize not resetting due to version conflict", USBGetVersion()); USBExpertStatusLevel(1,device, "\pUSB Device Extension is not paired with correct USB Support, USB may be flaky", 0); errataBits |= kErrataNoReset; } if( (errataBits & kErrataNoReset) != 0) { newInterfacesPB.pb.usbRefcon = kGetAConfiguration; /* Start out at first state which isn't reset */ } else { newInterfacesPB.pb.usbRefcon = kResetDevice; /* Start out at first state */ } // DebugStr("\pIn Composite Driver"); CompositeDeviceInitiateTransaction(&newInterfacesPB.pb); }